<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
	<meta http-equiv="pragma" content="no-cache" />
    <meta name="author" content="Jayli" />
	<meta name="keywords" content="淘宝UED 前端工程师 拔赤" />	
	<meta name="description" content="淘宝前端工程师拔赤，关注尖端前端技术，关注yui" />
	<meta http-equiv="imagetoolbar" content="no" />
	<meta name="title" content="拔赤的文章列表" />
    <title>基于yui的前端“团队开发”模式</title>
    <link href="http://jayli.github.com/blog/atom.xml" rel="alternate" title="setImpl" type="application/atom+xml" />
    <link rel="stylesheet" href="http://jayli.github.com/blog/media/css/style.css">
    <link rel="stylesheet" href="http://jayli.github.com/blog/media/css/github.css">
	<style>
	</style>
    <script type="text/javascript" src="http://jayli.github.com/blog/media/js/highlight.pack.js"></script>
    <script type="text/javascript">
      hljs.initHighlightingOnLoad();
    </script>
	<!--[if lte IE 8]>
	<script src="http://a.tbcdn.cn/apps/lottery/00023/index-v3/js/html5.js"></script>
	<![endif]-->
	<meta name="baidu-tc-verification" content="afb6c9df553ef3493d9ee65263df0d55" />
	<script src="http://siteapp.baidu.com/static/webappservice/uaredirect.js" type="text/javascript"></script><script type="text/javascript">uaredirect("http://m.zoojs.org", "http://jayli.github.com/blog");</script>
  </head>
  <body>
    <div id="container">
      <div id="main" role="main">
        <header>
        <h1>基于yui的前端“团队开发”模式</h1>
        </header>
        <nav>
        <span><a title="home page" class="" href="/blog/index.html">home</a></span>
        <span><a title="tags" class="" href="/blog/tags.html">tags</a></span>
        <span><a title="about" class="" href="/blog/about.html">about me</a></span>
        <span><a title="flickr" class="" href="http://www.flickr.com/photos/lijing00333">flickr</a></span>
        <span><a title="blogroll" class="" href="/blog/links.html">links</a></span>
        <span><a title="projects" class="" href="/blog/projects.html">projects</a></span>
        <span><a title="subscribe me" class="" href="/blog/atom.xml">feed</a></span>
        </nav>
        <article class="content">
        <section class="post">
<p>如今web项目也越来越大，单人开发一个网站已经不是什么新鲜事了，这种web项目规模扩大的速度似乎超过我们的想象，对代码的管理，对项目的控制，对分工的把握，对进度的高效推进……一系列的问题开始在web开发中显现出来，其实团队开发不是什么新东西，就像当年炒作ajax的概念一样，只是新瓶装旧酒罢了，只因互联网的丰富应用给了web工程师很多“创意”的空间，包括功能上、也包括技术上：比如google wave将10年前的聊天室技术做了包装，将长联接大胆应用于ajax中，再比如yui用面向团队面向对象的开发方法对web站点重新包装，使得web项目也具备类似erp的项目特点，在java风靡的年代大概还有些新意，再比如web开发中的迭代和极限编程则是10年前软件工程教科书上的东西……，因此 web行业本身没有太多新元素值得推崇，我们所做的，仅仅是在web高速发展的时候，将很多古老的方法应用其中而已。</p>

<p>刚才提到，web开发越来越依赖于团队，web项目也越来越具有完整、典型的生命周期：需求，设计，开发，测试，上线。这个过程会周而复始，并且会有多个周期的重叠或迭代。这使得我们越来越依赖传统软件工程学的方法，使用它来规范web项目的开发。</p>

<p>在大型web项目开发中，比较常用的是迭代模型。迭代是在一个主题项目中作类似增量开发的开发模式，它建立在主干代码相对稳定的基础上，适合项目革命性的版本升级不频繁的情况下使用。通常稳定的线上版本作为主干代码，如果在a时刻有新需求提出，则从此时从主干打出分支，在分支上针对a时刻的需求进行开发，开发完成并测试通过后将代码合并至主干。图中分支b在合并代码的时候和其母主干已经有区别，红色的部分就是新的“区别”，分支b在d时刻合并代码的时候，用 svn merge很方便，有冲突解决冲突，无冲突合并代码。</p>

<p>还有一种常用的开发模式：极限编程。极限编程是对团队成员要求很高的一种开发模式，每个成员负责的是一个方面而不是单独某个模块，比如一名php程序员负责项目中所有的后端程序，一名wd负责页面展示，一名项目经理，如果前端工作量很大的话顶多外加一名前端脚本工程师。整个项目的开发由这四人完成，而且完成既定需求的同时保持代码良好的结构、性能和可扩展。这种开发模式很精简也很快速，但这种项目往往不是孤立的，经常是一个大项目的子项目，或者仅仅是从主干拉出来的分支而已，每次快速开发后都会多少产生冗余，比如css、js或img文件不能被并行开发的其他分支共享，自然也无法重用，因此这种开发模式也仅仅适合工期短的项目开发。比如下图中的b分支。</p>

<p>然而在这两种典型的开发模式中，前端的开发一直处于一种尴尬境地，前端文件是一种资源文件，除了html页面之外，js、css和img文件是作为资源被 php文件使用的，因此js、css或img不像php文件那样，新功能开发完后可以直接覆盖掉原有文件，除了在svn中作备份以便回滚之外，并无版本的概念。而css、js和img在增加新功能后则不能覆盖原有文件，必须在文件名后缀上一个新的版本号另存一份，供新的php文件访问，而老版本的 css、js和img仍然被其他不确定的php文件引用着。</p>

<p>那么如果并发的多个分支项目中同时修改相同的js或css，问题就出现了，php代码可以合并到主干中，同一份js或css代码如何合并两个同时开发的版本呢？svn能解决部分问题，但解决不了根本问题，因此我们只有期望两个并发项目不会同时升级同一份js文件，也只有将js或css的粒度做到很细很细，即每个js或css文件都很小，只有一丁点的功能，这样小的功能被同时两个项目修改的概率自然会很低。可将js文件瓜分成众多小文件而且管理方便是何等不易。</p>

<p>yui很好的解决了这个问题，yui给出了一个高效拆分并管理js和css的思路：模块化。从yui2到yui3的过渡可以看到这种趋势，未来的 web项目但凡有点规模都需要模块化，在yui中，模块是分层次的，每个模块都有其依赖的子模块，子模块也有其依赖的孙模块，最后发现复杂的模块是由简单的模块拼装而成的。而每个模块都可以单独做成一个文件，这样就可以在项目开始之初，在前端架构阶段就规定好模块的粒度，这个粒度是取决于项目变化的程度的，变化越频繁，粒度就应当更高，以免并行项目对同一份js或css文件作更新。</p>

<p>这样的话，一个功能性的页面需要引用的只是一个页面逻辑的js文件，这个js文件去load其需要的模块，模块再去load各自需要的子模块以及孙模块，模块文件的递归load和去重由yui完成，我们只需要关注页面的js文件即可，每个模块都会自动去引用所需的css，不用我们操心。</p>

<p>如此高粒度的js文件和css文件在页面装载的时候是个大麻烦，下图是现在雅虎关系load的js文件，这还是在没有瓜分js模块的情况下，每个js文件占用一个请求，会大大降低页面的装载速度。</p>

<p>yui 给我们提供了combo的方法，但也仅仅针对yui的模块提供，对于项目中的js和css文件则没有combo的支持，yui3虽然是 beta版，至今也没有要支持的迹象，只要硬生生的去改yui源代码了。combo后的结果就是这样，yui2的资源和基于yui2的js文件以及 yui3的资源和基于yui3的js文件各一个请求，外加一个yuiloader.js和yui.js各一，这样yui2和yui3并存的情况下的js请求顶多也只有这4个了。</p>

<p>改 yui的代码也不费劲，在yui2中combo的处理是在的yuiloader.js中的<em>combine函数中，在yui3中则是yui.js 中的</em>combine中，可以根据自己的项目资源存储情况修改。这样，修改后的yui可以更广泛的支持combo，项目js文件就会和yui文件一并 combo输出，页面展示也会一下子从D上升到B或者A，哈哈。</p>

<p>在yui的框架下的前端开发变的如此高效率也更加轻松，这样的话，高粒度的js模块代替了功能性的js开发，更加有利于代码的抽象和重用，也大大降低了并行开发中升级同一个js文件的苦恼。项目迭代前进的效率也会越来越高，而前端页面的性能却丝毫不受影响。</p>

<p>你看看自己是否还在辛苦的压缩合并js呢？是否在苦恼的频繁累赘的升级js文件版本？如果是，那么很遗憾，你已经落伍了。</p>

</section>
<section class="meta">

<!--span class="tags">
  tagged by 
  
</span-->

<span class="time">
  posted at <time datetime="2008-10-14">2008-10-14</time>
</span>
</section>

<section class="comment">
<div id="disqus_thread"></div>
<script type="text/javascript">
    /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
    var disqus_shortname = 'jayliblog'; // required: replace example with your forum shortname
	var disqus_identifier = 'urn:uuid:3095e00d-d56c-46d7-99b0-4d336472e357';

    /* * * DON'T EDIT BELOW THIS LINE * * */
    (function() {
        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
        dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</section>


        </article>
      </div>
    </div> <!--! end of #container -->
  </body>
</html>
